func iNewLspServer(port int, params *LspParams) (*LspServer, error) { srv := new(LspServer) srv.nextId = 1 if params == nil { // Insert default parameters params = &LspParams{5, 2000} } srv.params = params hostport := fmt.Sprintf(":%v", port) addr, err := lspnet.ResolveUDPAddr("udp", hostport) if lsplog.CheckReport(1, err) { return nil, err } srv.udpConn, err = lspnet.ListenUDP("udp", addr) if lsplog.CheckReport(1, err) { return nil, err } srv.readBuf = NewBuf() // Need enough room to recycle close messages srv.appReadChan = make(LspMessageChan, 1) srv.appWriteChan = make(LspMessageChan) srv.netInChan = make(networkChan) srv.epochChan = make(chan int) srv.connById = make(map[uint16]*lspConn) srv.connByAddr = make(map[string]*lspConn) srv.closeReplyChan = make(chan error, 1) srv.closeAllReplyChan = make(chan error, 1) srv.writeReplyChan = make(chan error, 1) go srv.serverLoop() go srv.udpReader() go epochTrigger(srv.params.EpochMilliseconds, srv.epochChan, &srv.stopGlobalNetworkFlag) return srv, nil }
// Shut down all network activity func (srv *LspServer) stopGlobalNetwork() { srv.stopGlobalNetworkFlag = true err := srv.udpConn.Close() if lsplog.CheckReport(4, err) { lsplog.Vlogf(6, "Server Continuing\n") } }
// Write message to UDP connection. Address specified by con func (srv *LspServer) udpWrite(con *lspConn, msg *LspMessage) { b := msg.genPacket() _, err := srv.udpConn.WriteToUDP(b, con.addr) if lsplog.CheckReport(6, err) { srv.Vlogf(6, "Write failed\n") } }
// Shutting down network communications func (cli *LspClient) stopNetwork() { cli.lspConn.stopNetworkFlag = true err := cli.udpConn.Close() if lsplog.CheckReport(4, err) { lsplog.Vlogf(6, "Client Continuing\n") } }
// Write message to UDP connection. Address already registered with connection func (cli *LspClient) udpWrite(msg *LspMessage) { b := msg.genPacket() _, err := cli.udpConn.Write(b) if lsplog.CheckReport(6, err) { cli.Vlogf(6, "Write failed\n") } }
// Goroutine that reads messages from UDP connection and writes to message channel func (cli *LspClient) udpReader() { udpConn := cli.udpConn mc := cli.netInChan var buffer [1500]byte for !cli.lspConn.stopNetworkFlag { n, _, err := udpConn.ReadFromUDP(buffer[0:]) if lsplog.CheckReport(1, err) { cli.Vlogf(6, "Client continuing\n") continue } m, merr := extractMessage(buffer[0:n]) if lsplog.CheckReport(1, merr) { cli.Vlogf(6, "Client continuing\n") continue } mc <- m } }
// Goroutine that reads messages from UDP connection and writes to message channel func (srv *LspServer) udpReader() { udpConn := srv.udpConn netc := srv.netInChan var buffer [1500]byte for !srv.stopGlobalNetworkFlag { n, addr, err := udpConn.ReadFromUDP(buffer[0:]) if lsplog.CheckReport(1, err) { srv.Vlogf(5, "Server continuing\n") continue } m, merr := extractMessage(buffer[0:n]) if lsplog.CheckReport(1, merr) { srv.Vlogf(6, "Server continuing\n") continue } srv.Vlogf(5, "Received message %s\n", m) d := &networkData{m, addr} netc <- d } }
func iNewLspClient(hostport string, params *LspParams) (*LspClient, error) { cli := new(LspClient) if params == nil { // Insert default parameters params = &LspParams{5, 2000} } cli.params = params addr, err := lspnet.ResolveUDPAddr("udp", hostport) if lsplog.CheckReport(1, err) { return nil, err } cli.lspConn = newConn(addr, 0, 0) // Client's first received message will be data message. cli.lspConn.nextRecvSeqNum = NextSeqNum(0) cli.udpConn, err = lspnet.DialUDP("udp", nil, addr) if lsplog.CheckReport(1, err) { return nil, err } // Need enough room to recycle close messages at end cli.appReadChan = make(LspMessageChan, 2) cli.readBuf = NewBuf() cli.appWriteChan = make(LspMessageChan, 1) cli.netInChan = make(LspMessageChan, 1) cli.epochChan = make(chan int) cli.closeReplyChan = make(chan error, 2) cli.writeReplyChan = make(chan error, 2) go cli.clientLoop() go cli.udpReader() go epochTrigger(cli.params.EpochMilliseconds, cli.epochChan, &cli.lspConn.stopNetworkFlag) // Send connection request to server nm := GenConnectMessage() cli.udpWrite(nm) cli.lspConn.pendingMsg = nm cli.lspConn.nextSendSeqNum = NextSeqNum(0) cm := <-cli.appReadChan if cm.Type == MsgCONNECT { return cli, nil } return nil, lsplog.MakeErr("Connection failed") }
func (srv *LspServer) networkHandler() { lsplog.Vlogf(3, "[Server] Started the network handler") for { // Should loop only if the connection is still on. lsplog.Vlogf(6, "[Server] Going to read a packet") m, addr, err := srv.readPacket() if err != nil { lsplog.CheckReport(3, err) lsplog.Vlogf(6, "[Server] Ignoring this packet") continue } go srv.packetHandler(m, addr) } }
func main() { var ihelp *bool = flag.Bool("h", false, "Show help information") var iport *int = flag.Int("p", 6666, "Port number") var ihost *string = flag.String("H", "localhost", "Host address") var iverb *int = flag.Int("v", 1, "Verbosity (0-6)") var irdrop *int = flag.Int("r", 0, "Network read packet drop percentage") var iwdrop *int = flag.Int("w", 0, "Network write packet drop percentage") var elim *int = flag.Int("k", 5, "Epoch limit") var ems *int = flag.Int("d", 2000, "Epoch duration (millisecconds)") flag.Parse() if *ihelp { flag.Usage() os.Exit(0) } if flag.NArg() > 0 { // Look for host:port on command line ok := true fields := strings.Split(flag.Arg(0), ":") ok = ok && len(fields) == 2 if ok { *ihost = fields[0] n, err := fmt.Sscanf(fields[1], "%d", iport) ok = ok && n == 1 && err == nil } if !ok { flag.Usage() os.Exit(0) } } params := &lsp12.LspParams{*elim, *ems} lsplog.SetVerbose(*iverb) lspnet.SetReadDropPercent(*irdrop) lspnet.SetWriteDropPercent(*iwdrop) hostport := fmt.Sprintf("%s:%v", *ihost, *iport) fmt.Printf("Connecting to server at %s\n", hostport) cli, err := lsp12.NewLspClient(hostport, params) if err != nil { fmt.Printf("... failed. Error message %s\n", err.Error()) } if lsplog.CheckReport(1, err) { return } runclient(cli) }
func (cli *LspClient) readPacket() (m *LspMessage, addr *lspnet.UDPAddr, e error) { b := make([]byte, 1000) n, addr, err := cli.udpConn.ReadFromUDP(b) if addr == nil || n == 0 { lsplog.Vlogf(3, "[Client] Recieved a terminating packet.") return nil, addr, lsplog.ConnectionClosed() } else { lsplog.Vlogf(5, "[Client] Recieved a packet from %s:%d", addr.IP.String(), addr.Port) } if err != nil { lsplog.CheckFatal(err) return nil, nil, err } recieved := CreateEmptyPacket() err = json.Unmarshal(b[0:n], recieved) if err != nil { lsplog.CheckReport(3, err) return nil, addr, err } lsplog.Vlogf(6, "[Client] Recieved packet %+v", recieved) return recieved, addr, err }
func (srv *LspServer) readPacket() (m *LspMessage, addr *lspnet.UDPAddr, e error) { b := make([]byte, 1000) n, addr, err := srv.udpConn.ReadFromUDP(b) if addr == nil { lsplog.Vlogf(3, "[Server] Recieved a terminating packet.") return nil, addr, lsplog.ConnectionClosed() } else { lsplog.Vlogf(4, "[Server] Recieved a packet from %s:%d with length %d", addr.IP.String(), addr.Port, n) } if err != nil { lsplog.Vlogf(3, "[Server] Error occured while reading from UDP.") lsplog.CheckFatal(err) return nil, nil, err } recieved := CreateEmptyPacket() err = json.Unmarshal(b[0:n], recieved) if err != nil { lsplog.Vlogf(6, "[Server] Error while unmarshalling %X", b) lsplog.CheckReport(4, err) return nil, addr, err } lsplog.Vlogf(5, "[Server] Recieved packet %+v", recieved) return recieved, addr, err }
func (cli *LspClient) networkHandler() { lsplog.Vlogf(3, "[Client] Started the network handler") for { // Should loop only if the connection is still on. lsplog.Vlogf(6, "[Client] Going to read a packet") m, addr, err := cli.readPacket() if err != nil && addr == nil { // Found out that whenever a connection is closed, the address becomes nil. lsplog.CheckReport(3, err) lsplog.Vlogf(3, "[Client] Terminating network handler.") break } if err != nil { lsplog.CheckReport(3, err) continue } if !bytes.Equal(addr.IP, cli.udpAddr.IP) { lsplog.Vlogf(5, "[Client] Address of packet is unknown. Ignoring packet.") continue } lsplog.Vlogf(5, "[Client] Packet recieved is valid.") if IsConnectionAck(m) && !cli.connectionAlive { lsplog.Vlogf(5, "[Client] Connection acknowledged.") cli.connId = m.ConnId cli.makeConnectionAlive() } else if IsDataPacket(m) { lsplog.Vlogf(4, "[Client] Recieved a data packet from server.") if m.ConnId == cli.connId { lsplog.Vlogf(6, "[Client] Data packet belongs to this client.") if m.SeqNum == cli.serverSeqNum { lsplog.Vlogf(5, "[Client] Data packet has an expected sequence.") cli.read.Insert(m.Payload) cli.serverSeqNum = (cli.serverSeqNum + 1) % math.MaxInt8 lsplog.Vlogf(5, "[Client] Server sequence number became (%d).", cli.serverSeqNum) dataAck := CreateDataAck(cli.connId, m.SeqNum) cli.lastAck = dataAck cli.lspSend(dataAck) } else { lsplog.Vlogf(5, "[Client] Message sequence number (%d) in packet is not expected (%d).", m.SeqNum, cli.serverSeqNum) } } else { lsplog.Vlogf(4, "[Client] connId (%d) in packet is not the same as the client connId (%d).", m.ConnId, cli.connId) } } else { lsplog.Vlogf(4, "[Client] Recieved an acknowledgment packet from server.") <-cli.sentLocker deletedElements := list.New() for e := cli.sent.Front(); e != nil; e = e.Next() { sentMessage := e.Value.(*LspMessage) if sentMessage.SeqNum <= m.SeqNum { deletedElements.PushBack(e) } } for e := deletedElements.Front(); e != nil; e = e.Next() { cli.sent.Remove(e.Value.(*list.Element)) } cli.sentLocker <- 1 } cli.resetEpochCounter() } lsplog.Vlogf(3, "[Client] Terminated network handler") }