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
}
func iNewLspClient(hostport string, params *LspParams) (*LspClient, error) {
	client := new(LspClient)
	client.WBchan = make(chan *LspMessage, 1)
	client.Echan = make(chan int, 1)
	client.EchanBack = make(chan int, 1)
	client.Rchan = make(chan int)
	client.Wchan = make(chan int, 1)
	client.CloseChan = make(chan int, 1)
	client.CloseChanEpoch = make(chan int, 1)
	client.CloseNetworkChan = make(chan int, 1)
	client.RBchan = make(chan *LspMessage)
	client.eventHandClosedChan = make(chan int, 1)
	client.Nchan = make(chan *LspMessage, 1)
	client.established = make(chan int)
	client.writeEnded = make(chan int, 1)
	client.writeList = new(list.List)
	client.readList = new(list.List)
	client.errChan = make(chan error, 1)
	client.exitEpochHandler = make(chan int, 1)
	client.continueEpochHandler = make(chan int, 1)
	client.AckWrite = true
	client.allowWrite = true
	client.sn = 1
	client.rcvn = 1
	client.id = 0
	client.NbWrite = 0
	if params == nil {
		client.params = &LspParams{5, 2000}
	} else {
		client.params = params
	}
	addr, errResolve := lspnet.ResolveUDPAddr("udp", hostport)
	if errResolve != nil {
		return nil, errResolve
	}
	connexion, errDial := lspnet.DialUDP("udp", nil, addr)
	if errDial != nil {
		return nil, errDial
	}
	client.conn = connexion
	client.running = true
	msg, _ := buildMSG(MsgCONNECT, 0, 0, nil)
	client.writeList.PushBack(msg)
	client.NbWrite++
	client.lastWrite = msg
	client.Wchan <- 1
	client.epochCount = 0
	client.eventHandClosed = false
	go NetworkHandlerClient(client)
	go EpochHandlerClient(client)
	go EventHandlerClient(client)
	<-client.established
	return client, nil
}
func NewLoadBalancer(port int, monitorhostport string) *LoadBalancer {
	lb := new(LoadBalancer)
	lsplog.Vlogf(1, "[NewLoadBalancer] Dialing master... %v", monitorhostport)
	// connexion to monitor
	// server to communicate with workers
	lb.server, _ = lsp12.NewLspServer(port+10, &lsp12.LspParams{5, 2000})
	lb.monitor, _ = rpc.DialHTTP("tcp", monitorhostport)
	name, _ := os.Hostname()
	addrs, _ := net.LookupHost(name)
	lb.myAddress = addrs[0]
	args := &commproto.RegisterLoadBalancerArgs{fmt.Sprintf("%s:%v", addrs[0], port)}
	var reply commproto.RegisterLoadBalancerReply
	lb.monitor.Call("MonitorRPC.RegisterLoadBalancer", args, &reply)
	lsplog.Vlogf(1, "[NewLoadBalancer] Completed registration %s %+v", reply.Buddy, reply.LoadBalancersHostPort)
	lb.buddy = reply.Buddy
	lb.loadBalancers = reply.LoadBalancersHostPort
	// get workers
	lb.workers = reply.Workers
	lb.numberOfWorkers = len(lb.workers)
	lsplog.Vlogf(2, "[LoadBalancer] Establishing conn to workers")
	// establish RPC connexion load balancers
	lb.workersRPC = make(map[string]*rpc.Client)
	for i := 0; i < len(lb.workers); i++ {
		lb.workersRPC[lb.workers[i]], _ = rpc.DialHTTP("tcp", lb.workers[i])
	}
	lsplog.Vlogf(2, "[LoadBalancer] Establishing conn to LB")
	// establish RPC connexion with workers
	//numLbs := len(lb.loadBalancers)
	lb.LbsRPC = make(map[string]*rpc.Client)
	//for i := 0; i < numLbs; i ++ {
	//lb.LbsRPC[lb.loadBalancers[i]], _ = rpc.DialHTTP("tcp", lb.loadBalancers[i])
	//}
	lsplog.Vlogf(2, "[LoadBalancer] Established connections")
	lb.clientDict = make(map[uint16]*commproto.ClientS)
	lb.replicatedInformation = make(map[string]int)
	//lsplog.Vlogf(1, "[LoadBalancer] Received buddy: %s loadBalancers: %s", reply.Buddy, lb.loadBalancers)

	// connexion to switch
	addr, errResolve := lspnet.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port))
	if errResolve != nil {
		return nil
	}
	connexion, errDial := lspnet.ListenUDP("udp", addr)
	if errDial != nil {
		return nil
	}
	lb.connSwitch = connexion
	lsplog.Vlogf(1, "[LoadBalancer] Received buddy: %s loadBalancers: %s", reply.Buddy, lb.loadBalancers)

	go lb.runLoadBalancer()
	go lb.buddyHeartbeat()
	return lb
}
func (m *Monitor) startSwitch() {
	for i := 0; i < m.numberOfWorkers+m.numberOfLoadBalancers; i++ {
		<-m.informSwitch
	}
	addrs := make([]*lspnet.UDPAddr, m.numberOfLoadBalancers)
	i := 0
	for e := m.loadBalancers.Front(); e != nil; e = e.Next() {
		lb := e.Value.(*commproto.LoadBalancerInformation)
		addrs[i], _ = lspnet.ResolveUDPAddr("udp", lb.Hostport)
		i++
	}
	cli, _ := rpc.DialHTTP("tcp", m.switchHostPort)
	args := &commproto.RegisterArgs{NumLB: m.loadBalancers.Len(), Addrs: addrs}
	cli.Call("SwitchRPC.RegisterLoadBalancers", args, nil)
}
func NewSwitch(port int) *Switch {
	sw := new(Switch)
	sw.connId = 1
	sw.registered = make(chan bool, 1)
	addr, errResolve := lspnet.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port))
	if errResolve != nil {
		return nil
	}
	connexion, errListen := lspnet.ListenUDP("udp", addr)
	if errListen != nil {
		return nil
	}
	sw.srv = connexion
	go runServer(sw)
	return sw
}
func iNewLspServer(port int, params *LspParams) (*LspServer, error) {
	server := new(LspServer)
	server.ClientDict = make(map[uint16]*iClient)
	server.Wchan = make(chan int, 1)
	server.WBchan = make(chan *LspMessage, 1)
	server.Nchan = make(chan *LspMessage, 1)
	server.Echan = make(chan int, 1)
	server.EchanBack = make(chan int, 1)
	server.CloseChan = make(chan int, 1)
	server.CloseChanEpoch = make(chan int, 1)
	server.CloseNetworkChan = make(chan int, 1)
	server.eventHandClosedChan = make(chan int, 1)
	server.CloseConnChan = make(chan uint16, 1)
	server.Rchan = make(chan int)
	server.RBchan = make(chan *LspMessage)
	server.Addrchan = make(chan *lspnet.UDPAddr, 1)
	server.writeEnded = make(chan int, 1)
	server.errChan = make(chan error, 1)
	server.exitEpochHandler = make(chan int, 1)
	server.continueEpochHandler = make(chan int, 1)
	server.connId = 1
	server.NbWrite = 0
	server.readList = new(list.List)
	if params == nil {
		server.params = &LspParams{5, 2000}
	} else {
		server.params = params
	}
	addr, errResolve := lspnet.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port))
	if errResolve != nil {
		return nil, errResolve
	}
	connexion, errListen := lspnet.ListenUDP("udp", addr)
	if errListen != nil {
		return nil, errListen
	}
	server.conn = connexion
	server.running = true
	server.epochCount = 0
	server.eventHandClosed = false
	go NetworkHandlerServer(server)
	go EventHandlerServer(server)
	go EpochHandlerServer(server)
	return server, nil
}
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")
}